package awesome.cpu.structure;

import awesome.cpu.utils.Mode;

public class BranchCondGates extends NonSequentialComponent {
	
	public final static int KEY_PCWRITE_COND = 1;
	private int mPCWriteCond;
	public final static int KEY_FLAG = 2;
	private int mFlag;
	
	private static boolean outputDebug = false;
	
	public final static int KEY_RESULT = 3;
	//private int mResult;
	
	private final static BranchCondGates mInstance = new BranchCondGates();
	
	private BranchCondGates() {}

	public static BranchCondGates getInstance() {
		return mInstance;
	}

	@Override
	boolean setData(int keyInterface, int data) {
		switch (keyInterface) {
		case KEY_PCWRITE_COND:
			mPCWriteCond = data;
			return true;
		case KEY_FLAG:
			mFlag = data;
			return true;
		}
		return false;
	}

	@Override
	int getData(int keyInterface) {
		BusMonitor.transferData(Control.getInstance(), Control.KEY_PC_WRITE_CONDITION,
				this, KEY_PCWRITE_COND);
		BusMonitor.transferData(FlagRegister.getInstance(), FlagRegister.KEY_FLAG_ALL, 
				this, KEY_FLAG);
		
		switch (keyInterface) {
		case KEY_RESULT:
			int s = result();
			if (outputDebug && Mode.getDebugLevel() >= Mode.DEBUG_LEVEL_PRINT_ALL){
				System.out.println("BranchCondGates : cond = " + mPCWriteCond);
				System.out.println("BranchCondGates : flag = " + mFlag);
				System.out.println("BranchCondGates : result = " + s);
			}
			return s;
		}
		return 0;
	}

	private int result() {
		switch (mPCWriteCond) {
		case 0: // Z=1
			return (mFlag & FlagRegister.FLAG_Z) > 0 ? 1 : 0;
		case 1: // Z=0
			return (mFlag & FlagRegister.FLAG_Z) == 0 ? 1 : 0;
		case 2: // C=1
			return (mFlag & FlagRegister.FLAG_C) > 0 ? 1 : 0;
		case 3: // C=0
			return (mFlag & FlagRegister.FLAG_C) == 0 ? 1 : 0;
		case 4: // S=1
			return (mFlag & FlagRegister.FLAG_N) > 0 ? 1 : 0;
		case 5: // S=0
			return (mFlag & FlagRegister.FLAG_N) == 0 ? 1 : 0;
		case 6: // V=1
			return (mFlag & FlagRegister.FLAG_V) > 0 ? 1 : 0;
		case 7: // V=0
			return (mFlag & FlagRegister.FLAG_V) == 0 ? 1 : 0;
		case 8: // C=1 AND Z=0
			return ((mFlag & FlagRegister.FLAG_C) > 0 &&
					(mFlag & FlagRegister.FLAG_Z) == 0) ? 1 : 0;
		case 9: // C=0 OR Z=1
			return ((mFlag & FlagRegister.FLAG_C) == 0 ||
					(mFlag & FlagRegister.FLAG_Z) > 0) ? 1 : 0;
		case 10: // S=V
			return ((mFlag & FlagRegister.FLAG_N) > 0 &&
					(mFlag & FlagRegister.FLAG_V) > 0) ? 1 :
					  ((mFlag & FlagRegister.FLAG_N) == 0 &&
					(mFlag & FlagRegister.FLAG_V) == 0) ? 1 : 0;
		case 11: // NOT S=V
			return ((mFlag & FlagRegister.FLAG_N) > 0 &&
					(mFlag & FlagRegister.FLAG_V) == 0) ? 1 :
					  ((mFlag & FlagRegister.FLAG_N) == 0 &&
					(mFlag & FlagRegister.FLAG_V) > 0) ? 1 : 0;
		case 12: // Z=0 AND S=V
			return (mFlag & FlagRegister.FLAG_Z) > 0 ? 0 :
					((mFlag & FlagRegister.FLAG_N) > 0 &&
					(mFlag & FlagRegister.FLAG_V) > 0) ? 1 :
					((mFlag & FlagRegister.FLAG_N) == 0 &&
					(mFlag & FlagRegister.FLAG_V) == 0) ? 1 : 0;
		case 13: // Z=1 OR NOT S=V
			return (mFlag & FlagRegister.FLAG_Z) > 0 ? 1 :
					((mFlag & FlagRegister.FLAG_N) > 0 &&
					(mFlag & FlagRegister.FLAG_V) == 0) ? 1 :
					((mFlag & FlagRegister.FLAG_N) == 0 &&
					(mFlag & FlagRegister.FLAG_V) > 0) ? 1 : 0;
		}
		return 0;
	}
}
